#pragma once
#include "stdafx.h"
#include "Coordinates.h"
#include "Edge.h"
#include "Matrix.h"
#include "Plotter.h"


namespace HW2
{

	struct Polygon;
	struct ImageBitmap;
	struct PolygonData;


	struct Drawer
	{
		CDC* screen;
		Color color;

		Matrix transformation;
		Matrix projectionPerspective;
		Matrix projectionOrthographic;

		bool objectSpace;
		int centerX, centerY;
		void setCenter(int x, int y) { centerX = x; centerY = y;}

		Coordinates initialWindowSize;
		double scaleSize; // scale applied because of resize;

		double offsetZBeforeProjection;
		void setScreen(CDC* screen);
		void setColor(const Color &c);

		void reset();


		// Transform 3D to 2D
		Coordinates transformAndProject(Coordinates p);
		Coordinates transform(Coordinates p);
		Coordinates project(Coordinates p);

		void drawEdges(std::vector<Edge>& v);
		template<typename PLOTTER>
		void drawLineOnPlotter(Coordinates c1, Coordinates c2, PLOTTER &p, Coordinates beforeTransfoStart, Coordinates beforeTransfoEnd, Coordinates OriginalStart = Coordinates(), Coordinates OriginalEnd = Coordinates() );
		void drawLineOnPlotter(Coordinates c1, Coordinates c2, Plotter &p);

		void plot(int x, int y);
		void OnFinishFileLoad(int windowWidth, int windowHeight);

		// Apply a transformation;
		void apply(Matrix &m);

		// Low and High are the extreme cordinates of the object to draw
		static double getNiceRatio(Coordinates low, Coordinates high, int windowWidth, int windowHeight);


		// Update the "move" matrix by the specified number of pixels;
		void translate(double x, double y, double z);

		void scale(double ratio);

		void rotateX(double a);
		void rotateY(double a);
		void rotateZ(double a);

		// Modify the "d" of the perspective matrix;
		void modifyD(double scale);

		ImageBitmap generateBitmap(Polygon &p);
		PolygonData generatePolygonData(Polygon &p);

		void resize(int cx, int cy); // Resize the window, scale appropriately

		static Drawer& get()
		{
			static Drawer d;
			return d;
		}

	private:
		Drawer();
	};
}